package data;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.StartDocument;

import model.Basic;

/**
 * 
 * Reads/Writes to the Basic foods database. 
 * @author Roman Pusec, Dennis Goldfinger, Marko Bilic
 *
 */
public class BasicDao implements IDao<Basic> {

	private String filepath;
	static final String ITEM = "item";
	static final String NAME = "name";
	static final String CALORIES = "calories";
	static final String FAT = "fat";
    static final String PROTEIN = "protein";
    static final String CARBS = "carbs";
	
    /**
	 * Constructor which specifies the filepath. 
	 * @param filepath The path to the database. 
	 */
	public BasicDao(String filepath)
	{
		this.filepath = filepath;
	}
    
	/**
	 * Gets all of the Basic foods from the database. 
	 */
	@Override
	public ArrayList<Basic> getAll() {

	    ArrayList<Basic> items = new ArrayList<Basic>();
	    try {
	    	// First, create a new XMLInputFactory
	        XMLInputFactory inputFactory = XMLInputFactory.newInstance();
	        // Setup a new eventReader
	        InputStream in = new FileInputStream(filepath);
	        XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
	        // read the XML document
	        Basic basic = null;

	        while (eventReader.hasNext()) 
	        {
	        	XMLEvent event = eventReader.nextEvent();

		        if (event.isStartElement()) 
		        {
		        	StartElement startElement = event.asStartElement();
		            // If we have an item element, we create a new item
		            if (startElement.getName().getLocalPart() == (ITEM)) 
		            {
		        	    basic = new Basic("", 0, 0, 0, 0);
		            }
	   
					if (event.asStartElement().getName().getLocalPart().equals(NAME)) 
					{
					    event = eventReader.nextEvent();
					    basic.setName(event.asCharacters().getData());
					    continue;
					}
					
					if (event.asStartElement().getName().getLocalPart().equals(CALORIES)) 
		            {
		                event = eventReader.nextEvent();
		                basic.setCalories(Double.parseDouble(event.asCharacters().getData()));
		                continue;
		            }
		          
		            if (event.asStartElement().getName().getLocalPart().equals(FAT)) 
		            {
		                event = eventReader.nextEvent();
		                basic.setFat(Double.parseDouble(event.asCharacters().getData()));
		                continue;
		            }
		          
		            if (event.asStartElement().getName().getLocalPart().equals(PROTEIN)) 
		            {
			            event = eventReader.nextEvent();
			            basic.setProtein(Double.parseDouble(event.asCharacters().getData()));
			            continue;
		            }
	
		            if (event.asStartElement().getName().getLocalPart().equals(CARBS)) 
		            {
			            event = eventReader.nextEvent();
			            basic.setCarbs(Double.parseDouble(event.asCharacters().getData()));
			            continue;
		            }
		        }
		        // If we reach the end of an item element, we add it to the list
		        if (event.isEndElement()) 
		        {
		            EndElement endElement = event.asEndElement();
		            if (endElement.getName().getLocalPart() == (ITEM)) 
		            {
		            	items.add(basic);
		            }
		        }
	        
		    }
	    } catch (FileNotFoundException e) {
	      e.printStackTrace();
	    } catch (XMLStreamException e) {
	      e.printStackTrace();
	    }
	    return items;
	}
	
	/**
	 * Writes all of the Basic foods to the database. 
	 */
	@Override
	public void writeAll(ArrayList<Basic> basicArr) throws Exception {
		
		// create an XMLOutputFactory
	    XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
	    // create XMLEventWriter
	    XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(new FileOutputStream(filepath));
	    // create an EventFactory
	    XMLEventFactory eventFactory = XMLEventFactory.newInstance();
	    XMLEvent end = eventFactory.createDTD("\n");
	    XMLEvent tab = eventFactory.createDTD("\t");
	    // create and write Start Tag
	    StartDocument startDocument = eventFactory.createStartDocument();
	    eventWriter.add(startDocument);

	    // create config open tag
	    eventWriter.add(end);
	    StartElement itemsStartElement = eventFactory.createStartElement("", "", "items");
	    eventWriter.add(itemsStartElement);
	    eventWriter.add(end);
	    
	    for(Basic basic : basicArr)
	    {
	    	StartElement singleItemStartElement = eventFactory.createStartElement("", "", "item");
	    	eventWriter.add(tab);
	    	eventWriter.add(singleItemStartElement);
	    	eventWriter.add(end);
	    	
	    	// Write the different nodes
		    createNode(eventWriter, NAME, basic.getName());
		    createNode(eventWriter, CALORIES, Double.toString(basic.getCalories()));
		    createNode(eventWriter, FAT, Double.toString(basic.getFat()));
		    createNode(eventWriter, PROTEIN, Double.toString(basic.getProtein()));
		    createNode(eventWriter, CARBS, Double.toString(basic.getCarbs()));
		    
		    eventWriter.add(tab);
		    eventWriter.add(eventFactory.createEndElement("", "", "item"));
		    eventWriter.add(end);
	    }
	    
	    eventWriter.add(eventFactory.createEndElement("", "", "items"));
	    eventWriter.add(end);
	    eventWriter.add(eventFactory.createEndDocument());
	    eventWriter.close();
		
	}
	
	/**
	 * Creates a node in the XML file. 
	 * @param eventWriter The event writer. 
	 * @param name The name of the node. 
	 * @param value The value of the node. 
	 * @throws XMLStreamException 
	 */
	private void createNode(XMLEventWriter eventWriter, String name, String value) throws XMLStreamException 
	{	
	    XMLEventFactory eventFactory = XMLEventFactory.newInstance();
	    XMLEvent end = eventFactory.createDTD("\n");
	    XMLEvent tab = eventFactory.createDTD("\t\t");
	    // create Start node
	    StartElement sElement = eventFactory.createStartElement("", "", name);
	    eventWriter.add(tab);
	    eventWriter.add(sElement);
	    // create Content
	    Characters characters = eventFactory.createCharacters(value);
	    eventWriter.add(characters);
	    // create End node
	    EndElement eElement = eventFactory.createEndElement("", "", name);
	    eventWriter.add(eElement);
	    eventWriter.add(end);	
	}

}
